//+------------------------------------------------------------------+
//|                                                   ExpertBase.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Trade/SymbolInfo.h>       // 品种信息类（封装品种属性：点值、最小波动、保证金等）
#include <Trade/AccountInfo.h>      // 账户信息类（封装账户属性：余额、保证金模式、杠杆等）
#include <Trade/PositionInfo.h>     // 持仓信息类（读取持仓详情：手数、开仓价、止损止盈等）
#include <Trade/OrderInfo.h>        // 订单信息类（读取挂单/历史订单详情：类型、价格、状态等）
#include <Trade/DealInfo.h>         // 成交信息类（读取历史成交详情：成交价、时间、手续费等）
#include <Trade/HistoryOrderInfo.h> // 历史订单扩展类（读取历史订单完整生命周期数据）
#include <Indicators/Indicators.h>  // 指标集合类（管理技术指标与价格序列对象）

//+------------------------------------------------------------------+
//| 趋势类型枚举：定义不同强度的市场趋势，为策略提供趋势判断标准     |
//+------------------------------------------------------------------+
enum ENUM_TYPE_TREND
  {
   TYPE_TREND_HARD_DOWN  = 0,    // 极强下跌趋势（价格快速且持续下跌，伴随大成交量）
   TYPE_TREND_DOWN       = 1,    // 下跌趋势（价格稳步下跌，趋势明确）
   TYPE_TREND_SOFT_DOWN  = 2,    // 弱下跌趋势（价格震荡下行，趋势力度较弱）
   TYPE_TREND_FLAT       = 3,    // 无趋势（震荡行情，价格在区间内波动）
   TYPE_TREND_SOFT_UP    = 4,    // 弱上涨趋势（价格震荡上行，趋势力度较弱）
   TYPE_TREND_UP         = 5,    // 上涨趋势（价格稳步上涨，趋势明确）
   TYPE_TREND_HARD_UP    = 6     // 极强上涨趋势（价格快速且持续上涨，伴随大成交量）
  };

//+------------------------------------------------------------------+
//| 价格序列使用标志枚举：标记策略/组件需加载的价格相关数据类型       |
//+------------------------------------------------------------------+
enum ENUM_USED_SERIES
  {
   USE_SERIES_OPEN        = 0x1,  // 开盘价序列（K线开盘价格）
   USE_SERIES_HIGH        = 0x2,  // 最高价序列（K线最高价格）
   USE_SERIES_LOW         = 0x4,  // 最低价序列（K线最低价格）
   USE_SERIES_CLOSE       = 0x8,  // 收盘价序列（K线收盘价格，最常用的分析数据）
   USE_SERIES_SPREAD      = 0x10, // 点差序列（买卖价差值，影响交易成本）
   USE_SERIES_TIME        = 0x20, // K线时间序列（K线闭合时间，用于周期判断）
   USE_SERIES_TICK_VOLUME = 0x40, // Tick成交量序列（K线内的Tick数量，反映交易活跃度）
   USE_SERIES_REAL_VOLUME = 0x80  // 实际成交量序列（股票/期货等品种的成交手数，反映资金热度）
  };

//+------------------------------------------------------------------+
//| 初始化阶段枚举：控制对象配置修改权限，确保初始化流程的安全性     |
//+------------------------------------------------------------------+
enum ENUM_INIT_PHASE
  {
   INIT_PHASE_FIRST       = 0,    // 初始阶段（仅允许调用 Init() 方法，其他配置修改禁止）
   INIT_PHASE_TUNING      = 1,    // 调优阶段（允许修改品种、周期等核心配置，由 Init() 触发）
   INIT_PHASE_VALIDATION  = 2,    // 参数验证阶段（配置冻结，开始验证参数有效性，由 ValidationSettings() 触发）
   INIT_PHASE_COMPLETE    = 3     // 初始化完成阶段（所有配置锁定，对象可正常运行，由 InitIndicators() 触发）
  };

//+------------------------------------------------------------------+
//| 宏定义：快速判断是否启用特定价格序列，简化代码逻辑               |
//+------------------------------------------------------------------+
#define IS_OPEN_SERIES_USAGE         ((m_used_series & USE_SERIES_OPEN) != 0)
#define IS_HIGH_SERIES_USAGE         ((m_used_series & USE_SERIES_HIGH) != 0)
#define IS_LOW_SERIES_USAGE          ((m_used_series & USE_SERIES_LOW) != 0)
#define IS_CLOSE_SERIES_USAGE        ((m_used_series & USE_SERIES_CLOSE) != 0)
#define IS_SPREAD_SERIES_USAGE       ((m_used_series & USE_SERIES_SPREAD) != 0)
#define IS_TIME_SERIES_USAGE         ((m_used_series & USE_SERIES_TIME) != 0)
#define IS_TICK_VOLUME_SERIES_USAGE  ((m_used_series & USE_SERIES_TICK_VOLUME) != 0)
#define IS_REAL_VOLUME_SERIES_USAGE  ((m_used_series & USE_SERIES_REAL_VOLUME) != 0)

//+------------------------------------------------------------------+
//| CExpertBase 类：MQL5 EA 组件的基础基类                            |
//| 核心定位：封装所有 EA 组件（信号、资金、止损等）共用的基础能力，   |
//|           提供品种管理、价格序列加载、初始化流程控制等通用功能，   |
//|           统一各组件的接口标准，降低代码冗余与耦合度               |
//| 继承关系：派生自 CObject（MQL5 基础对象类，支持对象管理与内存安全）|
//| 适用场景：所有 EA 功能组件的父类（如 CExpertSignal、CExpertMoney），|
//|           为组件提供标准化的初始化、数据访问与配置管理能力         |
//+------------------------------------------------------------------+
class CExpertBase : public CObject
  {
protected:
   //----------------------------------------------------------------
   // 核心配置与状态变量（组件共用基础参数）
   //----------------------------------------------------------------
   ulong             m_magic;          // EA 魔术号（区分不同 EA 的订单，默认0，建议唯一）
   ENUM_INIT_PHASE   m_init_phase;     // 初始化阶段（控制配置修改权限）
   bool              m_other_symbol;   // 跨品种标志（true=使用非当前图表品种，需手动管理品种对象）
   CSymbolInfo      *m_symbol;         // 品种信息对象指针（封装品种属性：点值、最小波动等）
   bool              m_other_period;   // 跨周期标志（true=使用非当前图表周期，需手动加载对应周期数据）
   ENUM_TIMEFRAMES   m_period;         // 工作周期（如 PERIOD_H1=1小时线，默认当前图表周期）
   double            m_adjusted_point; // 调整后点值（适配3/5位小数品种，如JPY系货币对，避免计算误差）
   CAccountInfo      m_account;        // 账户信息对象（读取账户属性：保证金模式、余额、杠杆等）
   ENUM_ACCOUNT_MARGIN_MODE m_margin_mode; // 账户保证金模式（净值模式/对冲模式，影响持仓管理逻辑）
   ENUM_TYPE_TREND   m_trend_type;     // 当前市场趋势类型（由子类策略逻辑更新）
   bool              m_every_tick;     // 逐 Tick 计算标志（true=基于当前未闭合K线计算，适合短线策略）

   //----------------------------------------------------------------
   // 价格序列对象（封装不同类型的价格数据，提供高效访问接口）
   //----------------------------------------------------------------
   int               m_used_series;    // 价格序列使用标志（组合 ENUM_USED_SERIES 枚举值，标记需加载的序列）
   CiOpen           *m_open;           // 开盘价序列对象指针（访问K线开盘价数据）
   CiHigh           *m_high;           // 最高价序列对象指针（访问K线最高价数据）
   CiLow            *m_low;            // 最低价序列对象指针（访问K线最低价数据）
   CiClose          *m_close;          // 收盘价序列对象指针（访问K线收盘价数据，最常用）
   CiSpread         *m_spread;         // 点差序列对象指针（访问K线对应的点差数据）
   CiTime           *m_time;           // K线时间序列对象指针（访问K线闭合时间数据）
   CiTickVolume     *m_tick_volume;    // Tick成交量序列对象指针（访问K线内Tick数量数据）
   CiRealVolume     *m_real_volume;    // 实际成交量序列对象指针（访问股票/期货的成交手数数据）

public:
   //----------------------------------------------------------------
   // 构造与析构函数（确保对象初始化与资源安全释放）
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化基础对象状态
    * @details 1. 初始化核心配置变量（魔术号=0，保证金模式默认净值模式，趋势默认震荡）；
    *          2. 初始化价格序列对象指针为 NULL（后续通过 InitXXX 方法动态创建/绑定）；
    *          3. 设置初始化阶段为 INIT_PHASE_FIRST（仅允许调用 Init() 方法）。
    */
                     CExpertBase(void);

   /**
    * @brief 析构函数：释放对象占用的所有资源
    * @details 1. 若使用跨品种（m_other_symbol=true），删除自定义创建的品种信息对象；
    *          2. 若使用跨品种/跨周期，删除动态创建的价格序列对象，避免内存泄漏；
    *          3. 依赖 CObject 父类析构逻辑完成剩余资源清理。
    */
                    ~CExpertBase(void);

   //----------------------------------------------------------------
   // 状态与配置访问接口（获取/设置组件核心状态与参数）
   //----------------------------------------------------------------
   /**
    * @brief 获取当前初始化阶段
    * @return ENUM_INIT_PHASE - 初始化阶段（如 INIT_PHASE_TUNING=调优阶段）
    */
   ENUM_INIT_PHASE   InitPhase(void) const { return(m_init_phase); }

   /**
    * @brief 设置当前市场趋势类型（由子类策略逻辑调用，反映最新趋势判断）
    * @param value [in] 趋势类型（ENUM_TYPE_TREND 枚举值）
    */
   void              TrendType(ENUM_TYPE_TREND value) { m_trend_type = value; }

   /**
    * @brief 获取价格序列使用标志（仅非跨品种/跨周期时有效）
    * @return int - 价格序列使用标志（组合 ENUM_USED_SERIES 枚举值）
    */
   int               UsedSeries(void) const;

   /**
    * @brief 设置是否基于逐 Tick 计算（使用未闭合K线数据）
    * @param value [in] true=逐 Tick 计算（适合短线策略），false=仅基于已闭合K线（适合中长线策略）
    */
   void              EveryTick(bool value) { m_every_tick = value; }

   //----------------------------------------------------------------
   // 价格序列数据访问接口（快速获取指定索引的价格相关数据）
   //----------------------------------------------------------------
   /**
    * @brief 获取指定索引K线的开盘价
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 开盘价（失败返回 EMPTY_VALUE）
    */
   double            Open(int ind) const;

   /**
    * @brief 获取指定索引K线的最高价
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 最高价（失败返回 EMPTY_VALUE）
    */
   double            High(int ind) const;

   /**
    * @brief 获取指定索引K线的最低价
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 最低价（失败返回 EMPTY_VALUE）
    */
   double            Low(int ind) const;

   /**
    * @brief 获取指定索引K线的收盘价
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 收盘价（失败返回 EMPTY_VALUE）
    */
   double            Close(int ind) const;

   /**
    * @brief 获取指定索引K线对应的点差
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return int - 点差（失败返回 INT_MAX）
    */
   int               Spread(int ind) const;

   /**
    * @brief 获取指定索引K线的闭合时间
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return datetime - K线闭合时间（失败返回 0）
    */
   datetime          Time(int ind) const;

   /**
    * @brief 获取指定索引K线的 Tick 成交量（K线内的Tick数量）
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return long - Tick成交量（失败返回 0）
    */
   long              TickVolume(int ind) const;

   /**
    * @brief 获取指定索引K线的实际成交量（股票/期货的成交手数）
    * @param ind [in] K线索引（0=当前K线，1=前一根K线，以此类推）
    * @return long - 实际成交量（失败返回 0）
    */
   long              RealVolume(int ind) const;

   //----------------------------------------------------------------
   // 初始化与配置接口（完成组件基础参数设置与验证）
   //----------------------------------------------------------------
   /**
    * @brief 基础初始化（设置品种、周期、调整后点值，仅初始阶段可调用）
    * @param symbol [in] 品种信息对象指针（已初始化的 CSymbolInfo 实例）
    * @param period [in] 工作周期（ENUM_TIMEFRAMES 枚举值）
    * @param point [in] 调整后点值（适配3/5位小数品种）
    * @return bool - 初始化结果：true=成功，false=失败（如初始化阶段错误、指针无效）
    * @note 初始化成功后，将初始化阶段设为 INIT_PHASE_TUNING（允许修改配置）
    */
   virtual bool      Init(CSymbolInfo *symbol, ENUM_TIMEFRAMES period, double point);

   /**
    * @brief 设置工作品种（仅调优阶段可调用，支持跨品种交易）
    * @param name [in] 品种名称（如 "EURUSD"、"XAUUSD"）
    * @return bool - 设置结果：true=成功，false=失败（如初始化阶段错误、品种不存在）
    */
   bool              Symbol(string name);

   /**
    * @brief 设置工作周期（仅调优阶段可调用，支持跨周期交易）
    * @param value [in] 工作周期（ENUM_TIMEFRAMES 枚举值）
    * @return bool - 设置结果：true=成功，false=失败（如初始化阶段错误）
    */
   bool              Period(ENUM_TIMEFRAMES value);

   /**
    * @brief 设置 EA 魔术号（用于区分不同 EA 的订单，避免订单混淆）
    * @param value [in] 魔术号（32位无符号整数，建议唯一，如 123456）
    */
   void              Magic(ulong value) { m_magic = value; }

   /**
    * @brief 从账户信息中读取并设置保证金模式（净值模式/对冲模式）
    * @note 保证金模式影响持仓管理逻辑（如净值模式单品种单持仓，对冲模式支持多空同持）
    */
   void              SetMarginMode(void) { m_margin_mode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); }

   /**
    * @brief 验证配置参数有效性（仅调优阶段可调用，冻结配置修改）
    * @return bool - 验证结果：true=成功，false=失败（如初始化阶段错误）
    * @note 验证成功后，将初始化阶段设为 INIT_PHASE_VALIDATION（仅允许绑定价格序列）
    */
   virtual bool      ValidationSettings();

   //----------------------------------------------------------------
   // 价格序列绑定接口（绑定外部价格序列对象，仅参数验证阶段可调用）
   //----------------------------------------------------------------
   /**
    * @brief 绑定价格相关序列对象（开盘价、最高价、最低价、收盘价）
    * @param open [in] 开盘价序列对象指针
    * @param high [in] 最高价序列对象指针
    * @param low [in] 最低价序列对象指针
    * @param close [in] 收盘价序列对象指针
    * @return bool - 绑定结果：true=成功，false=失败（如初始化阶段错误、指针无效）
    */
   virtual bool      SetPriceSeries(CiOpen *open, CiHigh *high, CiLow *low, CiClose *close);

   /**
    * @brief 绑定其他辅助序列对象（点差、时间、成交量等）
    * @param spread [in] 点差序列对象指针
    * @param time [in] K线时间序列对象指针
    * @param tick_volume [in] Tick成交量序列对象指针
    * @param real_volume [in] 实际成交量序列对象指针
    * @return bool - 绑定结果：true=成功，false=失败（如初始化阶段错误、指针无效）
    */
   virtual bool      SetOtherSeries(CiSpread *spread, CiTime *time, CiTickVolume *tick_volume, CiRealVolume *real_volume);

   /**
    * @brief 初始化指标与价格序列（仅参数验证阶段可调用，完成初始化并锁定配置）
    * @param indicators [in] 指标集合对象指针（用于管理动态创建的价格序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如参数未验证、序列创建失败）
    * @note 1. 非跨品种/跨周期时，直接返回成功（使用外部传入的序列对象）；
    *       2. 跨品种/跨周期时，动态创建所需价格序列并添加到指标集合；
    *       3. 初始化成功后，将阶段设为 INIT_PHASE_COMPLETE（所有配置锁定）
    */
   virtual bool      InitIndicators(CIndicators *indicators = NULL);

protected:
   //----------------------------------------------------------------
   // 内部辅助方法：价格序列初始化（仅跨品种/跨周期时动态创建序列）
   //----------------------------------------------------------------
   /**
    * @brief 初始化开盘价序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitOpen(CIndicators *indicators);

   /**
    * @brief 初始化最高价序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitHigh(CIndicators *indicators);

   /**
    * @brief 初始化最低价序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitLow(CIndicators *indicators);

   /**
    * @brief 初始化收盘价序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitClose(CIndicators *indicators);

   /**
    * @brief 初始化点差序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitSpread(CIndicators *indicators);

   /**
    * @brief 初始化K线时间序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitTime(CIndicators *indicators);

   /**
    * @brief 初始化Tick成交量序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitTickVolume(CIndicators *indicators);

   /**
    * @brief 初始化实际成交量序列（创建对象、添加到指标集合、绑定品种与周期）
    * @param indicators [in] 指标集合对象指针（用于管理序列对象）
    * @return bool - 初始化结果：true=成功，false=失败（如对象创建失败、添加到集合失败）
    */
   bool              InitRealVolume(CIndicators *indicators);

   //----------------------------------------------------------------
   // 内部辅助方法：策略计算相关（子类可重写扩展，适配不同策略需求）
   //----------------------------------------------------------------
   /**
    * @brief 获取价格水平的计量单位（默认返回调整后点值，用于止损/止盈价格标准化）
    * @return double - 计量单位（如 0.0001 用于5位小数的 EURUSD，0.01 用于3位小数的 USDJPY）
    */
   virtual double    PriceLevelUnit(void) { return(m_adjusted_point); }

   /**
    * @brief 获取策略分析的起始K线索引（根据逐 Tick 标志决定是否包含未闭合K线）
    * @return int - 起始索引（0=包含当前未闭合K线，1=仅从已闭合K线开始）
    */
   virtual int       StartIndex(void) { return((m_every_tick ? 0 : 1)); }

   /**
    * @brief 验证订单魔术号是否与当前 EA 匹配（用于筛选当前 EA 管理的订单）
    * @param magic [in] 待验证的订单魔术号
    * @return bool - 验证结果：true=匹配，false=不匹配
    */
   virtual bool      CompareMagic(ulong magic) { return(m_magic == magic); }

   /**
    * @brief 判断账户是否为对冲模式（用于适配不同的持仓管理逻辑）
    * @return bool - 判断结果：true=对冲模式（支持多空同持），false=净值模式（单品种单持仓）
    */
   bool              IsHedging(void) const { return(m_margin_mode == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); }
  };
//+------------------------------------------------------------------+